package common

import (
	"net/http"

	"hundsun.com/hsl/hschain/common/types"

	"github.com/golang/protobuf/proto"
	"hundsun.com/hsl/hschain/common/crypto"
	"hundsun.com/hsl/hschain/common/log/logging"
	"hundsun.com/hsl/hschain/common/util/pb"
	"hundsun.com/hsl/hschain/protos"
	protoscomm "hundsun.com/hsl/hschain/protos/common"
	pbledger "hundsun.com/hsl/hschain/protos/ledger"
	"hundsun.com/hsl/hschain/protos/seqcenter"
)

// ValidateSequenceSignature 验证区块序列化签名信息
func ValidateSequenceSignature(block *pbledger.Block, log logging.Log) error {
	// 校验区块的sequence Signature
	if block.Header.BlockSequenceSignature != nil {
		if !VerifyBlockSequenceSignature(block, block.Header.BlockSequence, block.Header.BlockSequenceSignature, log) {
			return types.ErrInvalidSeqSignature
		}
	}
	return nil
}

// VerifyBlockSequenceSignature 验证区块序列号签名是否正确
func VerifyBlockSequenceSignature(block *pbledger.Block, blockSequence uint64, blockSequenceSignature *protoscomm.Signature, log logging.Log) bool {
	genesisTxPayload := pb.GetGenesisTransactionPayload()
	blockSequenceSignerAddress := protos.Address(genesisTxPayload.GetSequenceCenter().SignerAddress)

	// 1. 检查签名者是否是创世块中指定的
	actualBlkSeqSignerAddr, err := protos.ParseAddressFromPublicKeyBytes(blockSequenceSignature.PublicKey)
	if err != nil {
		log.Errorf("failed to parse signer address from block sequence signature [blockSequence=%d]: %s", blockSequence, err.Error())
		return false
	}

	if actualBlkSeqSignerAddr != blockSequenceSignerAddress {
		log.Errorf("unexpected signer '%s' of block sequence signature [blockSequence=%d]", actualBlkSeqSignerAddr, blockSequence)
		return false
	}

	// 2. 验证签名
	publicKey, err := crypto.ParserPublicKeyWithSignatureAlgorithm(blockSequenceSignature.PublicKey, int(blockSequenceSignature.Algorithm))
	if err != nil {
		log.Errorf("failed to parse public key from block sequence signature [blockSequence=%d]: %s", blockSequence, err.Error())
		return false
	}

	clonedResp := &seqcenter.SaveBlockResponse{
		StatusCode:    http.StatusOK,
		ErrorMessage:  "",
		BlockNumber:   block.Header.Number,
		BlockHash:     block.Hash(),
		BlockSequence: blockSequence,
		Signature:     nil,
	}

	data, err := proto.Marshal(clonedResp)
	if err != nil {
		log.Errorf("failed to unmarshal clonedResp[blockSequence=%d]: %s", blockSequence, err.Error())
		return false
	}
	ok, err := publicKey.Verify(data, blockSequenceSignature.Signature)
	if err != nil {
		log.Errorf("failed to verify block sequence signature [blockSequence=%d]: %s", blockSequence, err.Error())
		return false
	}
	return ok
}
